package lc;

import java.io.File;
import java.net.*;

/**
 * 首次探究自定义类加载器与热加载
 * https://www.cnblogs.com/silyvin/articles/10269681.html
 * https://www.cnblogs.com/silyvin/p/10267472.html
 */
public class Main {

    public static void main(String[] args) throws MalformedURLException, ClassNotFoundException, IllegalAccessException, InstantiationException {
//        String rootDir = "/Users/sunyuming/Downloads/jars/MyTest-1.0-SNAPSHOT.jar";
//        File file = new File(rootDir);
//        URI uri=file.toURI();
//        URL[] urls={uri.toURL()};

        System.out.println(System.getProperty("java.class.path"));
        System.out.println(System.getProperty("user.dir"));

        String dir = "file:/Users/sunyuming/Documents/tool/jars/MyTest-1.0-SNAPSHOT.jar";
        URL url = new URL(dir);
        URL[] urls2 = {url};

        // 若不指定parent参数，则默认由系统类加载器担任自定义类加载器的父加载器，输出parent:sun.misc.Launcher$AppClassLoader@3764951d
        MyUrlClassLoader myUrlClassLoader = new MyUrlClassLoader(urls2);
        System.out.println("parent:" + myUrlClassLoader.getParent());

        // 由于A在父加载器（系统类加载器）classpath下，根据双亲委派，优先由父加载器加载，输出A:sun.misc.Launcher$AppClassLoader@3764951d
        Class CA = myUrlClassLoader.loadClass("lc.A");
        System.out.println("A:" + CA.getClassLoader());

        // 打破双亲委派机制，直接使用findclass绕开从父加载器寻找并由父加载器加载这一步，输出A:lc.Main$MyUrlClassLoader@5acf9800
        // 当类加载请求到来时，先从缓存中查找该类对象，如果存在直接返回，如果不存在则交给该类加载去的父加载器去加载，倘若没有父加载则交给顶级启动类加载器去加载，最后倘若仍没有找到，则使用findClass()方法去加载
        CA = myUrlClassLoader.findClass("lc.A");
        System.out.println("A:" + CA.getClassLoader());

        // 实例化A，此时触发A的static代码块和B的加载，输出A:lc.Main$MyUrlClassLoader@5acf9800
        // 由于B在父加载器classpath下，优先由系统类加载器加载，输出B:sun.misc.Launcher$AppClassLoader@3764951d
        CA.newInstance();
    }


    private static class MyUrlClassLoader extends URLClassLoader {

        public MyUrlClassLoader(URL[] urls) {
            super(urls);
        }

        @Override
        protected Class<?> findClass(final String name) throws ClassNotFoundException {
            return super.findClass(name);
        }
    }
}